from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MinValueValidator, MaxValueValidator
import numpy as np


class Genre(models.Model):
    name = models.CharField(max_length=100)
    
    def __str__(self):
        return self.name


class Movie(models.Model):
    title = models.CharField(max_length=200)
    year = models.IntegerField()
    description = models.TextField()
    poster_url = models.URLField(blank=True, null=True)
    backdrop_url = models.URLField(blank=True, null=True)
    runtime = models.IntegerField(null=True, blank=True)
    imdb_id = models.CharField(max_length=20, blank=True, null=True)
    tmdb_id = models.IntegerField(blank=True, null=True)
    popularity = models.FloatField(default=0)
    vote_average = models.FloatField(default=0)
    vote_count = models.IntegerField(default=0)
    genres = models.ManyToManyField(Genre)
    
    def __str__(self):
        return f"{self.title} ({self.year})"
    
    def average_rating(self):
        ratings = self.rating_set.all()
        if ratings.exists():
            return sum([r.rating for r in ratings]) / len(ratings)
        return 0
    
    def recommend_similar_movies(self):
        """简单的基于用户评分的推荐系统"""
        user_movies = {}
        movie_users = {}
        
        # 构建电影-用户和用户-电影的字典
        for rating in Rating.objects.all():
            if rating.user_id not in user_movies:
                user_movies[rating.user_id] = {}
            user_movies[rating.user_id][rating.movie_id] = rating.rating
            
            if rating.movie_id not in movie_users:
                movie_users[rating.movie_id] = {}
            movie_users[rating.movie_id][rating.user_id] = rating.rating
        
        if self.id not in movie_users:
            # 如果没有评分，返回随机电影
            return Movie.objects.exclude(id=self.id).order_by('?')[:5]
        
        # 计算相似度
        similarity_scores = {}
        for movie_id in movie_users:
            if movie_id != self.id:
                similarity_scores[movie_id] = self._calculate_similarity(
                    movie_users[self.id], movie_users[movie_id]
                )
        
        # 返回最相似的5部电影
        similar_movie_ids = [
            movie_id for movie_id, score in 
            sorted(similarity_scores.items(), key=lambda x: x[1], reverse=True)[:5]
        ]
        
        return Movie.objects.filter(id__in=similar_movie_ids)
    
    def _calculate_similarity(self, users1, users2):
        """计算两部电影的相似度 (基于余弦相似度)"""
        common_users = set(users1.keys()) & set(users2.keys())
        if not common_users:
            return 0
        
        vec1 = [users1[user] for user in common_users]
        vec2 = [users2[user] for user in common_users]
        
        # 余弦相似度计算
        dot_product = sum(v1 * v2 for v1, v2 in zip(vec1, vec2))
        magnitude1 = sum(v ** 2 for v in vec1) ** 0.5
        magnitude2 = sum(v ** 2 for v in vec2) ** 0.5
        
        if magnitude1 == 0 or magnitude2 == 0:
            return 0
            
        return dot_product / (magnitude1 * magnitude2)


class Rating(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    rating = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
    comment = models.TextField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        unique_together = ('user', 'movie')
    
    def __str__(self):
        return f"{self.user.username}: {self.movie.title} - {self.rating}星" 